﻿#include "BoundingBoxSubBlock.h"
#include "Algorithm.h"
#include "GeneratedMesh.h"
#include "Types.h"
#include <vtkm/exec/ParametricCoordinates.h>

struct BoundingBoxSubBlockWorklet : vtkm::worklet::WorkletVisitCellsWithPoints
{
  using ControlSignature = void(CellSetIn, FieldInPoint, FieldOutCell blk_id);
  using ExecutionSignature = void(CellShape, _2, _3);

  BoundingBoxSubBlockWorklet(vtkm::Bounds box)
    : _bbox(box)
  {
  }
  template<typename CellShapeTag, typename PType>
  VTKM_EXEC void operator()(const CellShapeTag& shape, const PType& pts, vtkm::Int16& blk_id) const
  {
    vtkm::Vec3f lpoint;
    vtkm::exec::ParametricCoordinatesCenter(pts.GetNumberOfComponents(), shape, lpoint);
    typename PType::ComponentType center;
    vtkm::exec::ParametricCoordinatesToWorldCoordinates(pts, lpoint, shape, center);

    if (_bbox.Contains(center))
    {
      blk_id = -1;
    }
  };

  vtkm::Bounds _bbox;
};

RegisterObject(BoundingBoxSubBlock);
BoundingBoxSubBlock::BoundingBoxSubBlock(const Configuration& cfg)
  : MeshModifier(cfg)
{
  auto bottom_left = GetVectorValue<Real>("bottom_left");
  auto top_right = GetVectorValue<Real>("top_right");
  Vec3f min, max;
  if (bottom_left.size() == 1 && top_right.size() == 1)
  {
    min = Vec3f{ bottom_left[0], 0, 0 };
    max = Vec3f{ top_right[0], 0, 0 };
  }
  else if (bottom_left.size() == 2 && top_right.size() == 2)
  {
    min = Vec3f{ bottom_left[0], bottom_left[1], 0 };
    max = Vec3f{ top_right[0], top_right[1], 0 };
  }
  else if (bottom_left.size() == 3 && top_right.size() == 3)
  {
    min = Vec3f{ bottom_left[0], bottom_left[1], bottom_left[2] };
    max = Vec3f{ top_right[0], top_right[1], top_right[2] };
  }
  else
  {
    console::Error("BoundingBoxSubBlock: bottom_left or top_right size error...");
  }

  _bounding_box = vtkm::Bounds{ min, max };
}

BoundingBoxSubBlock::~BoundingBoxSubBlock() {}

void BoundingBoxSubBlock::Execute()
{
  ArrayHandle<vtkm::Int16> blk_id;
  vtkm::cont::Invoker{}(
    BoundingBoxSubBlockWorklet{ _bounding_box }, _mesh.GetCellSet(), _mesh.GetCoordinate(), blk_id);
}